#region Using Statements
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Chromos;
using Chromos.ActionEngine;
using Chromos.Actors;
#endregion

namespace Chromos.AIEngine
{
	public class ActorAIEngine
	{
		#region Fields
		/// <summary>
		/// How agressive the enemy is
		/// String values to pass in:
		/// "normal" is default set of moves and behavior
		/// "rough" is a slightly higher set of moves and behavior
		/// "super" is used by bosses only and are super moves and advanced behavior
		/// </summary>
		string aggressiveness;

		Random ran = new Random();

		public bool playerDectected = false;

		protected bool isIdle, isMovingLeft, isMovingRight, isAttacking, isDefending, isDying = false, isDead = false, isJumping;

		protected Actor actor;

		/// <summary>
		/// Distance that enemy can detect player
		/// Radius will change depending on the enemy
		/// Note: 15 is the default setting
		/// </summary>
		int detectionRadius = 300;
		double currentRadius = 1000;

		/// <summary>
		/// Player Position (x,y) on the map
		/// </summary>
		//Vector2 playerPos;
		#endregion

		#region Intialization

		/// <summary>
		/// Setup the enemy AI by passing in these parameters
		/// </summary>
		public ActorAIEngine(Actor actor, string aggressiveness, int detectionRadius)
		{
			this.aggressiveness = aggressiveness;
			this.detectionRadius = detectionRadius;
			this.actor = actor;
			setIdle();
			actor.getActionEngine().playAction(ActionType.Idle, 0);
        }
		#endregion

		#region Update
		#endregion

		#region Methods

		/// <summary>
		/// Detects the player
		/// </summary>
		/// <returns></returns>
		public bool DetectPlayer(Actor player)
		{
			/// <summary>
			/// Type of detection is using circles
			/// the enemies will have the circles
			/// centered at their positions and
			/// there radii will fluctuate
			/// with the type of enemies 
			/// </summary>
			//int radius = 20;

			if (actor.getDead() || player.getDead())
				return false;

			// if enemy circle and player position to 15 insersects then the player has been detected
			if ((
				currentRadius = Math.Sqrt((actor.position.X - player.position.X) * (actor.position.X - player.position.X) + 
				(actor.position.Y - player.position.Y) * (actor.position.Y - player.position.Y))) < this.detectionRadius)
			{
				// Engage player
				playerDectected = true;
			}

			return playerDectected;
		}

		/// <summary>
		 /// The object is passed in and based on agressiveness the
		/// values for speed and damage are changed.
		/// </summary>
		/// <param name="e"></param>
		public void SetAgressive(Enemy e)
		{
			//List<String> selectedMoves = new List<string>(4);

			if (this.aggressiveness.Equals("normal"))
			{
			}
			else if (this.aggressiveness.Equals("rough"))
			{
				// faster movement and more powerful attacks
			}
			else if (this.aggressiveness.Equals("super"))
			{
				// faster movement and more powerful attacks than rough
			}
		}

        public void reverseDirection()
        {
            if (getMovingLeft())
            {
                setMovingRight();
                actor.getActionEngine().stopAllActions();
                actor.getActionEngine().playAction(ActionType.Movement, 1);
            }
            else if (getMovingRight())
            {
                setMovingLeft();
                actor.getActionEngine().stopAllActions();
                actor.getActionEngine().playAction(ActionType.Movement, 0);
            }
            //velocity.X = -velocity.X;
        }

        public void collided()
        {
            this.reverseDirection();
        }

		public void setIdle()
		{
			isIdle = true;
			isMovingLeft = false;
			isMovingRight = false;
			//isAttacking = false;
			isDefending = false;
			//isDying = false;
            //isJumping = false;
		}
		public void setMovingLeft()
		{
			isIdle = false;
			isMovingLeft = true;
			isMovingRight = false;
			isAttacking = false;
			isDefending = false;
			//isDying = false;
		}
		public void setMovingRight()
		{
			isIdle = false;
			isMovingLeft = false;
			isMovingRight = true;
			isAttacking = false;
			isDefending = false;
			//isDying = false;
		}
		public void setAttacking()
		{
			isIdle = false;
			isMovingLeft = false;
			isMovingRight = false;
			isAttacking = true;
			isDefending = false;
			//isDying = false;
		}
		public void setDefending()
		{
			isIdle = false;
			isMovingLeft = false;
			isMovingRight = false;
			isAttacking = false;
			isDefending = true;
			//isDying = false;
		}
		public void setDying()
		{
			isIdle = false;
			isMovingLeft = false;
			isMovingRight = false;
			isAttacking = false;
			isDefending = false;
			isDying = true;
            isJumping = false;
		}
		public void setDead()
		{
			isDead = true;
		}
        public void setJumping()
        {
            isIdle = false;
            isJumping = true;
        }
        public void setNotJumping()
        {
            isJumping = false;
        }
        public bool getJumping()
        {
            return isJumping;
        }
		public bool getIdle()
		{
			return isIdle;
		}
		public bool getMovingLeft()
		{
			return isMovingLeft;
		}
		public bool getMovingRight()
		{
			return isMovingRight;
		}
		public bool getAttacking()
		{
			return isAttacking;
		}
		public bool getDefending()
		{
			return isDefending;
		}
		public bool getDying()
		{
			return isDying;
		}
		public bool getDead()
		{
			return isDead;
		}

		public virtual void kill()
		{
			if (!getDying() && !getDead())
			{
				setDying();
				actor.getActionEngine().stopAllActionsWithForce();
				actor.getActionEngine().playAction(ActionType.Death, 0);
			}
		}
		#endregion

		public void update()
		{
			if (actor is Enemy)
			{
				playerDectected = DetectPlayer(actor.game.player);

				// Check for feasible attacks
				if (playerDectected)
				{
					bool attackPicked = false;
					List<AttackAction> attacks = actor.getActionEngine().getAttacks();
					for (int i = 0; i < attacks.Count; i++)
					{
						attacks.ElementAt(i).lastAttacked += actor.game.timeSinceLastUpdate;
						if (!attackPicked && attacks.ElementAt(i).range >= currentRadius)
						{
							if (ran.NextDouble() < (double)attacks.ElementAt(i).closeFreq/100)
							{
								// Reset lastAttacked to 0 if we can attack again now
								if (attacks.ElementAt(i).lastAttacked > attacks.ElementAt(i).rate && attacks.ElementAt(i).facing == actor.getFacing())
								{
									if (actor.getFacing() == FACING.LEFT && actor.game.player.position.X <= actor.position.X ||
										actor.getFacing() == FACING.RIGHT && actor.game.player.position.X >= actor.position.X)
									{
										attacks.ElementAt(i).lastAttacked = 0;
										actor.getActionEngine().playAction(ActionType.Attack, i);
										actor.game.player.attack(attacks.ElementAt(i).damage);
										attackPicked = true;
									}
								}
							}
						}
					}
				}
			}
		}
	}
}